package drawing;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;

import javax.swing.JComponent;

import utils.MyEventClass;
import utils.MyEventClassListener;

public class DrawingComponent extends JComponent {

	State state = State.IDLE;
	boolean mMove = false;
	private BufferedImage _bufImage = null;
	int s_x, s_y, e_x, e_y;
	List<Shape> shapes = new ArrayList<Shape>();
	Stack<Shape> toAdd = new Stack<Shape>();
	private List _listeners = new ArrayList();

	public DrawingComponent() {
		this.setBackground(Color.WHITE);
		this.addListeners();
	}

	public void paint(Graphics g) {
		Graphics2D g2 = (Graphics2D) g;
		this.paintComponent(g2);
	}

	public void paintComponent(Graphics g) {
		super.paintComponent(g);

		Graphics2D g2 = (Graphics2D) g;
		if (_bufImage == null) {
			int w = this.getWidth();
			int h = this.getHeight();
			_bufImage = (BufferedImage) this.createImage(w, h);
			Graphics2D gc = _bufImage.createGraphics();
			gc.setColor(Color.white);
			gc.fillRect(0, 0, w, h);
		}
		g2.drawImage(_bufImage, null, 0, 0);

		drawCurrentShape(g2);
	}

	private void drawCurrentShape(Graphics2D g2) {
		Shape s = null;
		if (state.equals(State.ELLIPSE)) {
			int width = Math.abs(e_x - s_x);
			int height = Math.abs(e_y - s_y);
			s = new Ellipse2D.Double(s_x, s_y, width, height);
		} else if (state.equals(State.RECT)) {
			int width = Math.abs(e_x - s_x);
			int height = Math.abs(e_y - s_y);
			s = new Rectangle(s_x, s_y, width, height);
		} else if (state.equals(State.LINE)) {
			s = new Line2D.Double(s_x, s_y, e_x, e_y);
		} else if (state.equals(State.PEN)) {

		}
		if (s != null)
			g2.draw(s);
		if (s != null && mMove == false) {
			if (!shapes.contains(s)) {
				shapes.add(s);
				fireEvent(s);
			}
		}

	}

	public State getState() {
		return state;
	}

	public void setState(State state) {
		this.state = state;
	}

	private void forceRepaint() {
		this.repaint();
	}

	public List<Shape> getShapes() {
		return shapes;
	}

	public void setShapes(List<Shape> shapes) {
		this.shapes = shapes;
	}

	private void addListeners() {
		this.addMouseListener(new MouseListener() {

			@Override
			public void mouseClicked(MouseEvent arg0) {
			}

			@Override
			public void mouseEntered(MouseEvent arg0) {
				// TODO Auto-generated method stub

			}

			@Override
			public void mouseExited(MouseEvent arg0) {
				// TODO Auto-generated method stub

			}

			@Override
			public void mousePressed(MouseEvent arg0) {
				if (state != state.IDLE) {
					mMove = true;
					s_x = arg0.getX();
					s_y = arg0.getY();
				}

			}

			@Override
			public void mouseReleased(MouseEvent arg0) {
				if (mMove && state != State.IDLE) {
					e_x = arg0.getX();
					e_y = arg0.getY();

					Graphics2D grafarea = _bufImage.createGraphics();
					drawCurrentShape(grafarea);

					forceRepaint();
					mMove = false;
				}

			}
		});

		this.addMouseMotionListener(new MouseMotionListener() {

			@Override
			public void mouseDragged(MouseEvent e) {
				// TODO Auto-generated method stub
				if (mMove) {
					e_x = e.getX();
					e_y = e.getY();
					forceRepaint();
				}
			}

			@Override
			public void mouseMoved(MouseEvent e) {

			}
		});
	}

	public void addFigure(Shape figure) {
		Graphics2D g2 = this._bufImage.createGraphics();
		g2.draw(figure);
		this.repaint();

	}

	public synchronized void addEventListener(MyEventClassListener listener) {
		_listeners.add(listener);
	}

	public synchronized void removeEventListener(MyEventClassListener listener) {
		_listeners.remove(listener);
	}

	// call this method whenever you want to notify
	// the event listeners of the particular event
	private synchronized void fireEvent(Shape s) {
		MyEventClass event = new MyEventClass(s);
		Iterator i = _listeners.iterator();
		while (i.hasNext()) {
			((MyEventClassListener) i.next()).handleMyEventClassEvent(event);
		}
	}

}
